; keyboard.asm
; Keyboard input handling

	.include "common.inc"
	.include "global.inc"
	.include "scancodes.inc"
	.include "petscii.inc"
	.include "window.inc"
	.include "timer.inc"
	
	.export keyb_irq
	.export init_keyboard
	.export do_keyboard
	
	KEY_BUF_SIZE = 80
	
	SHIFT_CTRL_FLAG = $028D
	
	KEYMAP_TABLE	= $EC46 
	KEYMAP1			= $EC5E

	.segment "DATA"
	
keybuf:		.res KEY_BUF_SIZE
ktailp:		.byte $00
kheadp:		.byte $00

lastrow:	.res 8

mask:		.byte $00
code:		.byte $00

keyevent:	.tag KeyEvent

	.segment "RODATA"
	
codeoff:	.byte $00, $08, $10, $18, $20, $28, $30, $38
	
	.segment "CODE"

do_keyboard: ; fetch scancodes from buffer
			jsr getkey		; get key code
			bcc @fin
			asl				; press or release?
			ldx #EVT_KEY_DOWN
			bcc @settype
			ldx #EVT_KEY_UP	; store type
@settype:	stx keyevent+KeyEvent::type
			lsr				; store scan code
			sta keyevent+KeyEvent::scncode
			tay
			lda KEYMAP1, y	; check for dead keys
			cmp #8
			bcs @nodeadkey
			cpy #SCAN_CODE_RSHIFT
			bne @store
			lda #DEAD_KEY_RSHIFT
@store:		eor keyevent+KeyEvent::ddstate
			sta keyevent+KeyEvent::ddstate
			; get petscii for scan code
@nodeadkey:	lda keyevent+KeyEvent::ddstate
			cmp #DEAD_KEY_RSHIFT	
			bcc @norshift
			and #DEAD_KEY_RSHIFT-1
			ora #DEAD_KEY_LSHIFT
@norshift:	asl
			tax
			lda KEYMAP_TABLE, x
			sta reg0
			lda KEYMAP_TABLE+1, x
			sta reg0+1
			lda (reg0), y
			sta keyevent+KeyEvent::petscii
			jsr pet2scr
			sta keyevent+KeyEvent::scrcode
			jsr kset_event
			jmp do_keyboard
@fin:		rts

kset_event:	lda #<keyevent
			ldx #>keyevent
			jmp win_event

keyb_irq:	lda #%01111111	; setup mask
			sta VIA2_BASE+0
			ldx #7
@deloop:	lda VIA2_BASE+1		; get row
			cmp VIA2_BASE+1
			bne @deloop
			ldy #%10000000	; setup mask
			sty mask
			tay
			eor lastrow, x	; check for changes
			beq @norchg
			pha
			tya
			sta lastrow, x
			pla
			ldy #7
@coloop:	asl				; check columns
			bcc @nocol
			clc				; calc scancode
			pha
			tya
			adc codeoff, x
			sta code
			lda lastrow, x	; press or release?
			and mask
			beq @noflag
			lda #$80		; set bit 7 for release
@noflag:	ora code
			jsr putkey		; store key code
			pla
@nocol:		lsr mask		; next column
			dey				
			bpl @coloop		
@norchg:	ror VIA2_BASE+0		; next row
			dex
			bpl @deloop			
			lda #$F7		; reset port
			sta VIA2_BASE+0
			rts

putkey:		; add scan code (A) to key buffer
			sta code		; save code
			txa				; save X
			pha
			ldx ktailp		; increment tail pointer
			jsr next
			cpx kheadp		; buffer full (next(tail) = head) ?
			beq @fin
			lda code		; write code
			sta keybuf, x
			stx ktailp		; set new tail
@fin:		pla				; restore X
			tax
			jmp notify_activity
						
next:		inx
			cpx #KEY_BUF_SIZE
			bcc @novl
			ldx #0			
@novl:		rts			
			
getkey:		; get scan code from keybuffer (-> A, Carry = success, -> X .. headp)
			ldx kheadp		; buffer empty (head = tail)?
			cpx ktailp
			beq @fin
			jsr next		; increment head pointer
			lda keybuf, x	; get code
			stx kheadp		; set new head
			sec				; -> success
			rts
@fin:		clc				; -> failure
			rts

init_keyboard:
			lda #0			; clear dead key state
			sta keyevent+KeyEvent::ddstate
			lda #$FF		; init last row values
			ldx #7			
@clrloop:	sta lastrow, x
			dex
			bpl @clrloop
flush_keyb:	sei				; flush keybuf
			lda #0
			sta ktailp
			sta kheadp
			cli
			rts
